//package declarations
package pxgrid_entities;

//imports
import java.util.*;

/**
 * PXJob
 * A entity class to store attributes about a job.
 * 
 * @author Mark Bate
 */
public class PXJob {
    //variables
    //job & grid info variables
    private String job_name;
    private int grid_job_id;
    private String grid_controller;
    private String grid_type;
    
    //phaser input variables
    private String input_mtz;
    private String input_pdb;
    private String space_group;
    private String f_label;
    private String sigf_label;
    private double molecular_weight;
    private int number_of_molecules_in_asymmetric_unit;
    private int number_of_copies_of_ensemble_to_search_for;
    private double rmsd;
    private int packing;
    
    //phaser output variables
    private String output_pdb;
    private String output_mtz;
    private String output_sol;
    private String output_sum;
    private String job_stdout;
    private double z_score;
    private double log_likelihood_gain;
    
    //xgrid job status variables
    private String status;
    private boolean is_suspended;
    private Date submission_time;
    private Date start_time;
    private Date stop_time;
    
    //an ArrayList to contain valid space groups
    private ArrayList<String> valid_space_groups;
    
    
    /**
     * constructor
     */
    public PXJob() {

        this.valid_space_groups = new ArrayList();
        this.valid_space_groups.add("P1");
        this.valid_space_groups.add("P2");
        this.valid_space_groups.add("P21");
        this.valid_space_groups.add("C2");
        this.valid_space_groups.add("P222");
        this.valid_space_groups.add("P2221");
        this.valid_space_groups.add("P21212");
        this.valid_space_groups.add("P2122");
        this.valid_space_groups.add("P2212");
        this.valid_space_groups.add("P21221");
        this.valid_space_groups.add("P22121");
        this.valid_space_groups.add("P212121");
        this.valid_space_groups.add("C222");
        this.valid_space_groups.add("C2221");
        this.valid_space_groups.add("C222A");
        this.valid_space_groups.add("C2221A");
        this.valid_space_groups.add("F222");
        this.valid_space_groups.add("I222");
        this.valid_space_groups.add("I212121");
        this.valid_space_groups.add("I222A");
        this.valid_space_groups.add("P4");
        this.valid_space_groups.add("P41");
        this.valid_space_groups.add("P42");
        this.valid_space_groups.add("P43");
        this.valid_space_groups.add("P422");
        this.valid_space_groups.add("P4122");
        this.valid_space_groups.add("P4222");
        this.valid_space_groups.add("P4322");
        this.valid_space_groups.add("P4212");
        this.valid_space_groups.add("P41212");
        this.valid_space_groups.add("P42212");
        this.valid_space_groups.add("P42212A");
        this.valid_space_groups.add("P43212");
        this.valid_space_groups.add("I4");
        this.valid_space_groups.add("I41");
        this.valid_space_groups.add("I422");
        this.valid_space_groups.add("I4122");
        this.valid_space_groups.add("P3");
        this.valid_space_groups.add("P31");
        this.valid_space_groups.add("P32");
        this.valid_space_groups.add("P312");
        this.valid_space_groups.add("P3112");
        this.valid_space_groups.add("P3212");
        this.valid_space_groups.add("P321");
        this.valid_space_groups.add("P3121");
        this.valid_space_groups.add("P3221");
        this.valid_space_groups.add("R3");
        this.valid_space_groups.add("R32");
        this.valid_space_groups.add("P6");
        this.valid_space_groups.add("P61");
        this.valid_space_groups.add("P65");
        this.valid_space_groups.add("P62");
        this.valid_space_groups.add("P64");
        this.valid_space_groups.add("P63");
        this.valid_space_groups.add("P622");
        this.valid_space_groups.add("P6122");
        this.valid_space_groups.add("P6522");
        this.valid_space_groups.add("P6222");
        this.valid_space_groups.add("P6422");
        this.valid_space_groups.add("P6322");
        this.valid_space_groups.add("P23");
        this.valid_space_groups.add("P213");
        this.valid_space_groups.add("P432");
        this.valid_space_groups.add("P4232");
        this.valid_space_groups.add("P4332");
        this.valid_space_groups.add("P4132");
        this.valid_space_groups.add("I23");
        this.valid_space_groups.add("I213");
        this.valid_space_groups.add("I432");
        this.valid_space_groups.add("I4132");
        this.valid_space_groups.add("H32");
        this.valid_space_groups.add("ALL");
    }
    
    /**
     * sets the name of a job
     * @param job_name String the name of the job
     */
    public void setJobName(String job_name) {
        this.job_name = job_name;
    }
    
    /**
     * sets the job ID that the grid has assigned to this job
     * @param grid_job_id int the ID assigned to the job by the grid
     * @throws java.lang.Exception throw if grid_job_id is negative
     */
    public void setGridJobID(int grid_job_id) throws Exception {
        if(grid_job_id >= 0) {
            this.grid_job_id = grid_job_id;
        } else {
            throw new Exception("xgrid_job_id must be an integer 0 or greater");
        }
    }
    
    /**
     * sets the display name of the grid controller that job was submitted to
     * @param grid_controller String the display name of the grid controller
     */
    public void setGridController(String grid_controller) {
        this.grid_controller = grid_controller;
    }
    
    /**
     * sets the type of grid the job has been submitted to
     * @param grid_type String the type of grid the job is being submitted to
     */
    public void setGridType(String grid_type) {
        this.grid_type = grid_type;
    }
    
    /**
     * sets the path (relative from submission root) of the input MTZ file
     * @param input_mtz String relative path to the input MTZ file
     */
    public void setInputMTZ(String input_mtz) {
        //put some stuff here to check if file exists - MB
        this.input_mtz = input_mtz;
    }
    
    /**
     * sets the path (relative from submission root) of the input PDB file
     * @param input_pdb String relative path to the input PDB file
     */
    public void setInputPDB(String input_pdb) {
        //put some stuff here to check if file exists - MB
        this.input_pdb = input_pdb;
    }
    
    /**
     * sets the space group for the job
     * @param space_group String the space group to use for the job
     * @throws java.lang.Exception thrown if the space_group is not in the 
     * valid_space_groups ArrayList
     */
    public void setSpaceGroup(String space_group) throws Exception {
        
        if(this.valid_space_groups.contains(space_group.toUpperCase()))
            this.space_group = space_group.toUpperCase();
        else
            throw new Exception("space groups entered is not valid");
    }
    
    /**
     * sets the F Label of the MTZ file
     * @param f_label String the F Label
     */
    public void setFLabel(String f_label) {
        this.f_label = f_label;
    }
    
    /**
     * sets the SIGF Label of the MTZ file
     * @param sigf_label String the SIGF Label
     */
    public void setSigfLabel(String sigf_label) {
        this.sigf_label = sigf_label;
    }
    
    /**
     * sets the molecular weight of the data
     * @param molecular_weight double the molecular weight
     * @throws java.lang.Exception thrown if the molecular weight is zero or less
     */
    public void setMolecularWeight(double molecular_weight) throws Exception {
        if(molecular_weight > 0)
            this.molecular_weight = molecular_weight;
        else
            throw new Exception("molecular_weight must be an integer greater than 0");
    }
    
    /**
     * sets the number of molecules in the asymmetric unit
     * @param number_of_molecules_in_asymmetric_unit int
     * @throws java.lang.Exception thrown if zero or less
     */
    public void setNumberOfMoleculesInAsymmetricUnit(int number_of_molecules_in_asymmetric_unit) throws Exception {
        if (number_of_molecules_in_asymmetric_unit > 0)
            this.number_of_molecules_in_asymmetric_unit = number_of_molecules_in_asymmetric_unit;
        else
            throw new Exception("number of molecules in asymmetric unit must be an integer greater than 0");
    }
    
    /**
     * sets the number of copies of the ensemble to search for
     * @param number_of_copies_of_ensemble_to_search_for int
     * @throws java.lang.Exception thrown if zero or less
     */
    public void setNumberOfCopiesOfEnsembleToSearchFor(int number_of_copies_of_ensemble_to_search_for) throws Exception {
        if (number_of_copies_of_ensemble_to_search_for > 0)
            this.number_of_copies_of_ensemble_to_search_for = number_of_copies_of_ensemble_to_search_for;
        else
            throw new Exception("number of copies of ensemble to search for must be an integer greater than 0");
    }
    
    /**
     * sets the root mean square deviation to use for phaser
     * @param rmsd double the root mean square deviation
     * @throws java.lang.Exception thrown if zero or less
     */
    public void setRMSD(double rmsd) throws Exception {
        if(rmsd > 0)
            this.rmsd = rmsd;
        else
            throw new Exception("rmsd must be a float greater than 0");
    }
    
    /**
     * sets the Packing tolerance to be used by phaser
     * @param packing int the packing tolerance
     * @throws java.lang.Exception thrown if the tolerance is less than zero
     */
    public void setPacking(int packing) throws Exception {
        if(packing >= 0)
            this.packing = packing;
        else
            throw new Exception("packing must be an integer greater than or equal to 0");
    }
    
    /**
     * sets the output PDB file of the job (relative to submission results dir)
     * @param output_pdb String the path to the output PDB file
     */
    public void setOutputPDB(String output_pdb) {
        this.output_pdb = output_pdb;
    }
    
    /**
     * sets the output MTZ file of the job (relative to submission results dir)
     * @param output_mtz String the path to the output MTZ file
     */
    public void setOutputMTZ(String output_mtz) {
        this.output_mtz = output_mtz;
    }
    
    /**
     * sets the output SOL file of the job (relative to submission results dir)
     * @param output_sol String the path to the output SOL file
     */
    public void setOutputSol(String output_sol) {
        this.output_sol = output_sol;
    }
    
    /**
     * sets the output SUM file of the job (relative to submission results dir)
     * @param output_sum String the path to the output SUM file
     */
    public void setOutputSum(String output_sum) {
        this.output_sum = output_sum;
    }
    
    /**
     * sets the stdout of the job as a String
     * @param job_stdout String the stdout of the job
     */
    public void setJobStdout(String job_stdout) {
        this.job_stdout = job_stdout;
    }
    
    /**
     * sets the Z Score returned by the phaser job
     * @param z_score double the Z Score of the job
     * @throws java.lang.Exception thrown if Z Score is less than zero
     */
    public void setZScore(double z_score) throws Exception {
        if(z_score >= 0 )
            this.z_score = z_score;
        else
            throw new Exception("z_score must be a float greater than or equal to 0");
    }

    /**
     * sets the log likelihood gain returned by the phaser job
     * @param log_likelihood_gain double the log likelihood gain phaser returned
     */
    public void setLogLikelihoodGain(double log_likelihood_gain) {
            this.log_likelihood_gain = log_likelihood_gain;
    }

    /**
     * sets the status of the job (as returned by the grid)
     * @param status String the status of the job according to the grid
     */
    public void setStatus(String status) {
        this.status = status;
    }

    /**
     * sets whether the job is suspended or not according to the grid.
     * @param is_suspended Boolean whether the job is suspended or not.
     */
    public void setIsSuspended(boolean is_suspended) {
        this.is_suspended = is_suspended;
    }
    
    /**
     * sets the date/time the job was submitted to the grid
     * @param submission_time Date the date the job was submitted to the grid
     * @throws java.lang.Exception thrown if the date is before 01 jan 2008.
     */
    public void setSubmissionTime(Date submission_time) throws Exception {
        //Theoretically submitting a job before 01 jan 2008 is impossible.
        //Note: MR Grid has not been tested at speeds of 88 mph or above.
        if(submission_time.getTime() >  1199163600)
            this.submission_time = submission_time;
        else
            throw new Exception("submission_timestamp must be a timestamp greater than midnight on 01 jan 2008");
    }
    
    /**
     * sets the date/time the job was started by the grid
     * @param start_time Date the date the job was started by the grid
     * @throws java.lang.Exception thrown if the date is before 01 jan 2008.
     */
    public void setStartTime(Date start_time) throws Exception {
        //Theoretically submitting a job before 01 jan 2008 is impossible.
        //Note: MR Grid has not been tested at speeds of 88 mph or above.
        if(start_time.getTime() >  1199163600)
            this.start_time = start_time;
        else
            throw new Exception("start_time must be a Date greater than midnight on 01 jan 2008");
    }
    
    /**
     * sets the date/time the job was finished by the grid
     * @param stop_time Date the date the job was finished by the grid
     * @throws java.lang.Exception thrown if the date is before 01 jan 2008.
     */
    public void setStopTime(Date stop_time) throws Exception {
        //Theoretically submitting a job before 01 jan 2008 is impossible.
        //Note: MR Grid has not been tested at speeds of 88 mph or above.
        if(stop_time.getTime() >  1199163600)
            this.stop_time = stop_time;
        else
            throw new Exception("stop_time must be a Date greater than midnight on 01 jan 2008");
    }
    
    
    //get methods
    
    /**
     * gets the name of the job
     * @return String the name of the job
     */
    public String getJobName() {
        return this.job_name;
    }
   
    /**
     * gets the ID the grid assigned to the job
     * @return int the ID assigned by the grid to the job
     */
    public int getGridJobID() {
        return this.grid_job_id;
    }
    
    /**
     * gets the display name of the grid controller
     * @return String the display name of the controller
     */
    public String getGridController() {
        return this.grid_controller;
    }
    
    /**
     * gets the type of grid the job was submitted to
     * @return String the type of grid job was submitted to
     */
    public String getGridType() {
        return this.grid_type;
    }
    
    /**
     * gets the input MTZ file used for this job
     * @return String the path of the MTZ file used for this job, relative to
     * the root of the submission
     */
    public String getInputMTZ() {
        return this.input_mtz;
    }
    
    /**
     * gets the input PDB file used for the job
     * @return String the path of the PDB file used for this job, relative to
     * the root of the submission
     */
    public String getInputPDB() {
        return this.input_pdb;
    }
    
    /**
     * gets the space group to be searched by phaser
     * @return String the space group used for this job
     */
    public String getSpaceGroup() {
        return this.space_group;
    }
    
    /**
     * gets the F Label of the MTZ file
     * Note: this does not read the MTZ, the variable must be set with the
     * corresponding set method.
     * @return String the F Label of the MTZ file
     */
    public String getFLabel() {
        return this.f_label;
    }
    
    /**
     * gets the SIGF Label of the MTZ file
     * Note: this does not read the MTZ, the variable must be set with the
     * corresponding set method.
     * @return String the SIGF Label of the MTZ file
     */
    public String getSigfLabel() {
        return this.sigf_label;
    }
    
    /**
     * gets the molecular weight of the data
     * Note: this does not read from the MTZ, the variable must be set with the
     * corresponding method.
     * @return double the molecular weight of the data
     */
    public double getMolecularWeight() {
        return this.molecular_weight;
    }
    
    /**
     * gets the number of molecules in the asymmetric unit
     * Note: this does not read from the MTZ, variable must be set using the 
     * set method
     * @return int number of molecules in the asymmetric unit
     */
    public int getNumberOfMoleculesInAsymmetricUnit() {
        return this.number_of_molecules_in_asymmetric_unit;
    }
    
    /**
     * gets the number of copies of the search ensembles to search for.
     * Eg. find 2 instances of it.
     * @return int number of copies if the search ensemble to search for
     */
    public int getNumberOfCopiesOfEnsembleToSearchFor() {
        return this.number_of_copies_of_ensemble_to_search_for;
    }
    
    /**
     * gets the root mean squared deviation to be used for the job
     * @return double the root mean squared deviation used
     */
    public double getRMSD() {
        return this.rmsd;
    }
    
    /**
     * gets the packing tolerance to be used
     * @return int the packing tolerance
     */
    public int getPacking() {
        return this.packing;
    }
    
    /**
     * gets the path of the output PDB file, relative to the submission results 
     * directory
     * @return String relative path of the output PDB file
     */
    public String getOutputPDB() {
        return this.output_pdb;
    }
    
    /**
     * gets the path of the output MTZ file, relative to the submission results 
     * directory
     * @return String relative path of the output MTZ file
     */
    public String getOutputMTZ() {
        return this.output_mtz;
    }
    
    /**
     * gets the path of the output SOL file, relative to the submission results 
     * directory
     * @return String relative path of the output SOL file
     */
    public String getOutputSol() {
        return this.output_sol;
    }
    
    /**
     * gets the path of the output SUM file, relative to the submission results 
     * directory
     * @return String relative path of the output SUM file
     */
    public String getOutputSum() {
        return this.output_sum;
    }
    
    /**
     * returns the stdout of the phaser run as a String
     * @return String the stdout from the pahser run
     */
    public String getJobStdout() {
        return this.job_stdout;
    }
    
    /**
     * returns the Z Score of the job
     * @return double the Z Score returned by phaser
     */
    public double getZScore() {
        return this.z_score;
    }
    
    /**
     * returns the Log Likelihood Gain of the job
     * @return double the Log Likelihood Gain returned by phaser
     */
    public double getLogLikelihoodGain() {
        return this.log_likelihood_gain;
    }
    
    /**
     * gets the status of the job as returned by the grid
     * @return String the status of the jobs according to the grid
     */
    public String getStatus() {
        return this.status;
    }
    
    /**
     * gets whether the job is suspended or not
     * @return Boolean whether the job is suspended or not
     */
    public Boolean getIsSuspended() {
        return this.is_suspended;
    }
    
    /**
     * get the Date/Time that job was submitted to the grid
     * @return Date the date/time job was submitted to the grid
     */
    public Date getSubmissionTime() {
        return this.submission_time;
    }
    
    /**
     * get the Date/Time that job was started by the grid
     * @return Date the date/time job was started by the grid
     */
    public Date getStartTime() {
        return this.start_time;
    }
    
    /**
     * get the Date/Time that job was finished by the grid
     * @return Date the date/time job was finished by the grid
     */
    public Date getStopTime() {
        return this.stop_time;
    }

}
